import { useControlController, useNamespace } from '@ibiz-template/vue3-util';
import {
  computed,
  defineComponent,
  nextTick,
  PropType,
  ref,
  resolveComponent,
  watch,
} from 'vue';
import { MenuItem } from '@imengyu/vue3-context-menu';
import { createUUID } from 'qx-util';
import {
  IDETBGroupItem,
  IDETBRawItem,
  IDETBUIActionItem,
  IDEToolbarItem,
  IDETree,
  IDETreeNode,
} from '@ibiz/model-core';
import {
  IButtonContainerState,
  IButtonState,
  ITreeNodeData,
  TreeNodeData,
} from '@ibiz-template/runtime';
import { TreeController } from './tree.controller';
import './tree.scss';

export const TreeControl = defineComponent({
  name: 'IBizTreeControl',
  props: {
    modelData: { type: Object as PropType<IDETree>, required: true },
    context: { type: Object as PropType<IContext>, required: true },
    params: { type: Object as PropType<IParams>, default: () => ({}) },
    /**
     * 部件行数据默认激活模式
     * - 0 不激活
     * - 1 单击激活
     * - 2 双击激活(默认值)
     *
     * @type {(number | 0 | 1 | 2)}
     */
    mdctrlActiveMode: { type: Number, default: 2 },

    /**
     * 是否为单选
     * - true 单选
     * - false 多选
     *
     * @type {(Boolean)}
     */
    singleSelect: { type: Boolean, default: true },
    defaultExpandedKeys: { type: Array as PropType<string[]> },
  },
  setup() {
    const c = useControlController((...args) => new TreeController(...args));
    const ns = useNamespace(`control-${c.model.controlType!.toLowerCase()}`);
    const treeRef = ref<IData>();

    const setCheckedNodes = () => {
      if (c.state.singleSelect) {
        treeRef.value!.setCurrentKey(c.state.selectedData[0]?.id || null);
      } else {
        // el-tree，会把没选中的反选，且不触发check事件
        treeRef.value!.setCheckedNodes(c.state.selectedData);
      }
    };

    /** 树展示数据 */
    const treeData = computed(() => {
      if (!c.state.isLoaded) {
        return [];
      }
      return c.model.rootVisible
        ? c.state.rootNodes
        : c.state.rootNodes.reduce<ITreeNodeData[]>((result, nodeData) => {
            if (nodeData.children) {
              return result.concat(nodeData.children);
            }
            return result;
          }, []);
    });

    // 根节点数据变更时重绘tree
    const treeRefreshKey = ref('');
    watch(treeData, (newVal, oldVal) => {
      if (newVal !== oldVal) {
        treeRefreshKey.value = createUUID();
        console.log('treeDataChange', newVal);
      }
    });

    /**
     * 触发节点加载数据
     * @author lxm
     * @date 2023-05-29 09:16:07
     * @param {IData} item
     * @param {(nodes: IData[]) => void} callback
     */
    const loadData = async (
      item: IData,
      callback: (nodes: IData[]) => void,
    ) => {
      let nodes: IData[];
      if (item.level === 0) {
        nodes = treeData.value;
        ibiz.log.debug('初始加载');
      } else if (item.data instanceof TreeNodeData) {
        if (item.data.children) {
          ibiz.log.debug('节点展开加载-本地', item.data);
          nodes = item.data.children;
        } else {
          ibiz.log.debug('节点展开加载-远程', item.data);
          nodes = await c.loadNodes(item.data);
        }
      } else {
        ibiz.log.error('未考虑到的情况', item, item.data);
        return;
      }
      ibiz.log.debug('给树返回值', nodes);
      callback(nodes);
    };

    // 值变更优化，加载成功后的值变更需要等渲染完成之后执行，其他情况不用
    let selectionWait = false;
    c.evt.on('onLoadSuccess', () => {
      selectionWait = true;
      setTimeout(() => {
        selectionWait = false;
      }, 200);
    });

    // 选中数据回显
    c.evt.on('onSelectionChange', async () => {
      if (selectionWait) {
        await nextTick();
      }
      setCheckedNodes();
    });

    /**
     * 多选时选中节点变更
     */
    const onCheck = (
      nodeData: ITreeNodeData,
      opts: { checkedNodes: ITreeNodeData[] },
    ) => {
      const { checkedNodes } = opts;
      c.setSelection(checkedNodes);
    };

    let forbidClick: boolean = false;
    /**
     * 节点单击事件
     */
    const onNodeClick = (nodeData: ITreeNodeData, evt: MouseEvent) => {
      evt.stopPropagation();
      if (forbidClick) {
        return;
      }
      c.onTreeNodeClick(nodeData);
      forbidClick = true;
      setTimeout(() => {
        forbidClick = false;
      }, 200);
    };

    /**
     * 节点双击事件
     */
    const onNodeDbClick = (nodeData: ITreeNodeData, evt: MouseEvent) => {
      evt.stopPropagation();
      c.onDbTreeNodeClick(nodeData);
    };

    // *上下文菜单相关 /

    let ContextMenu: IData;
    c.evt.on('onMounted', () => {
      // 有上下文菜单时加载组件
      if (Object.values(c.state.contextMenus).length > 0) {
        const importMenu = () => import('@imengyu/vue3-context-menu');
        importMenu().then(value => {
          ContextMenu = value.default;
        });
      }
    });

    const iBizRawItem = resolveComponent('IBizRawItem');
    const iBizIcon = resolveComponent('IBizIcon');

    /**
     * 计算上下文菜单组件配置项集合
     */
    const calcContextMenuItems = (
      toolbarItems: IDEToolbarItem[],
      nodeData: ITreeNodeData,
      evt: MouseEvent,
      menuState: IButtonContainerState,
    ): MenuItem[] => {
      const result: MenuItem[] = [];
      toolbarItems.forEach(item => {
        if (item.itemType === 'SEPERATOR') {
          result.push({
            divided: 'self',
          });
          return;
        }

        const buttonState = menuState[item.id!] as IButtonState;
        if (buttonState && !buttonState.visible) {
          return;
        }

        // 除分隔符之外的公共部分
        const menuItem: MenuItem = {};
        if (item.showCaption && item.caption) {
          menuItem.label = item.caption;
        }
        if (item.sysImage && item.showIcon) {
          menuItem.icon = <iBizIcon icon={item.sysImage}></iBizIcon>;
        }

        // 界面行为项
        if (item.itemType === 'DEUIACTION') {
          menuItem.disabled = buttonState.disabled;
          menuItem.clickClose = true;
          const { uiactionId } = item as IDETBUIActionItem;
          if (uiactionId) {
            menuItem.onClick = () => {
              c.doUIAction(uiactionId, nodeData, evt);
            };
          }
        } else if (item.itemType === 'RAWITEM') {
          const { rawItem } = item as IDETBRawItem;
          if (rawItem) {
            menuItem.label = (
              <iBizRawItem rawItem={item as IDETBRawItem}></iBizRawItem>
            );
          }
        } else if (item.itemType === 'ITEMS') {
          // 分组项绘制子菜单
          if ((item as IDETBGroupItem).detoolbarItems?.length) {
            menuItem.children = calcContextMenuItems(
              (item as IDETBGroupItem).detoolbarItems!,
              nodeData,
              evt,
              menuState,
            );
          }
        }
        result.push(menuItem);
      });

      return result;
    };

    /**
     * 节点右键菜单点击事件
     */
    const onNodeContextmenu = async (
      nodeData: ITreeNodeData,
      evt: MouseEvent,
    ) => {
      // 阻止原生浏览器右键菜单打开
      evt.preventDefault();
      const nodeModel = c.getNodeModel(nodeData.nodeId);
      if (!nodeModel?.decontextMenu?.detoolbarItems?.length) {
        return;
      }

      // 更新菜单的权限状态
      const menuState = c.state.contextMenus[nodeModel.decontextMenu.id!];
      await menuState.update(
        nodeData.deData || (nodeData.srfkey ? nodeData : undefined),
        nodeModel.appDataEntityId,
      );

      const menus: MenuItem[] = calcContextMenuItems(
        nodeModel.decontextMenu.detoolbarItems,
        nodeData,
        evt,
        menuState,
      );
      if (!menus.length) {
        return;
      }

      ContextMenu.showContextMenu({
        x: evt.x,
        y: evt.y,
        customClass: ns.b('context-menu'),
        items: menus,
      });
    };

    /**
     * 绘制上下文菜单触发图标
     * @param nodeModel
     * @param nodeData
     * @returns
     */
    const renderContextMenu = (
      nodeModel: IDETreeNode,
      nodeData: ITreeNodeData,
    ) => {
      if (!nodeModel?.decontextMenu?.detoolbarItems?.length) {
        return;
      }

      return (
        <div
          class={ns.b('context-menu-trigger')}
          onClick={(evt: MouseEvent) => onNodeContextmenu(nodeData, evt)}
        >
          <ion-icon
            class={ns.be('context-menu-trigger', 'caption-icon')}
            name='ellipsis-horizontal'
          />
        </div>
      );
    };

    return {
      c,
      ns,
      treeRef,
      treeData,
      treeRefreshKey,
      onCheck,
      onNodeClick,
      onNodeDbClick,
      onNodeContextmenu,
      loadData,
      renderContextMenu,
    };
  },
  render() {
    return (
      <iBizControlBase controller={this.c}>
        {this.c.state.isLoaded && this.treeRefreshKey && (
          <el-tree
            ref={'treeRef'}
            key={this.treeRefreshKey}
            node-key='id'
            highlight-current
            // 点击节点的时候不展开
            expand-on-click-node={false}
            show-checkbox={!this.c.state.singleSelect}
            default-expanded-keys={this.c.state.expandedKeys}
            props={{
              label: 'text',
              children: 'children',
              isLeaf: 'leaf',
            }}
            lazy
            load={this.loadData}
            onCheck={this.onCheck}
          >
            {{
              default: ({ data }: { data: ITreeNodeData }) => {
                const nodeModel = this.c.getNodeModel(data.nodeId)!;
                return (
                  <div
                    onDblclick={evt => this.onNodeDbClick(data, evt)}
                    onClick={evt => this.onNodeClick(data, evt)}
                    onContextmenu={evt => this.onNodeContextmenu(data, evt)}
                    class={[this.ns.b('node'), nodeModel.sysCss?.cssName]}
                  >
                    {nodeModel.sysImage && (
                      <iBizIcon
                        class={this.ns.be('node', 'icon')}
                        icon={nodeModel.sysImage}
                      ></iBizIcon>
                    )}
                    <span class={this.ns.be('node', 'label')}>{data.text}</span>
                    {this.renderContextMenu(nodeModel, data)}
                  </div>
                );
              },
            }}
          </el-tree>
        )}
      </iBizControlBase>
    );
  },
});
